﻿using System;
using System.Threading;
using NsbExtensions.Endpoint.Management;
using NsbExtensions.Messages.Management.Monitoring;
using NsbExtensions.Tests.Stubs;
using NUnit.Framework;
using NUnit.Framework.SyntaxHelpers;
using ObjectBuilder;
using ObjectBuilder.SpringFramework;

namespace NsbExtensions.Tests.EndpointTests
{
    [TestFixture]
    public class EndpointClientManagementServiceTestFixture
    {
        private TestMessagingEndpoint Endpoint;
        private IBuilder Builder;
        private EndpointManagementClientService MgtService;


        [TestFixtureSetUp]
        public void FixtureSetUp()
        {
            Builder = new Builder();
            Endpoint = (TestMessagingEndpoint) TestMessagingEndpoint.Create(Builder);

            Builder.ConfigureComponent(typeof (EndpointManagementClientService), ComponentCallModelEnum.Singleton)
                .ConfigureProperty("StatusReportGracePeriod", TimeSpan.FromMinutes(10));

            MgtService = Builder.Build<EndpointManagementClientService>();

            Endpoint.AddLocalBackgroundService(MgtService);
        }

        [TestFixtureTearDown]
        public void FixtureTearDown()
        {
            if (Endpoint != null)
                Endpoint.Dispose();
        }

        [Test]
        public void OnlineOfflineMonitor()
        {
            var bus = (TestBus) Endpoint.Bus;

            Endpoint.Start();

            Assert.AreEqual(1, bus.SentMessages.Count);
            Assert.IsTrue(bus.SentMessages[0].Message is EndpointOnlineNotification);

            Endpoint.TakeEndpointOffline("Test", TimeSpan.FromHours(2));

            Assert.AreEqual(2, bus.SentMessages.Count);
            Assert.IsTrue(bus.SentMessages[1].Message is EndpointOfflineNotification);

            var msg = (EndpointOfflineNotification) bus.SentMessages[1].Message;

            Assert.AreEqual("Test", msg.OfflineReason);
            Assert.AreEqual(120, msg.EstimatedOutageDurationInMinutes);
        }

        [Test]
        public void StartStopTest()
        {
            Endpoint.Start();

            Assert.IsTrue(MgtService.IsRunning);

            Endpoint.Stop();

            Assert.IsFalse(MgtService.IsRunning);
        }

        [Test]
        public void StatusMonitorTest()
        {
            MgtService.StatusReportInterval = TimeSpan.FromMilliseconds(100);
            MgtService.AddStatusProbe(new TestStatusProbe {Name = "TestProbe1"});
            MgtService.AddStatusProbe(new TestStatusProbe {Name = "TestProbe2", Value = "1.15457"});

            var bus = (TestBus) Endpoint.Bus;

            bus.SentMessages.Clear();

            Endpoint.Start();

            Thread.Sleep(150);

            Endpoint.Stop();

            Assert.AreEqual(3, bus.SentMessages.Count);
            Assert.IsTrue(bus.SentMessages[1].Message is EndpointStatusMessage);

            var statusUpdate = (EndpointStatusUpdateNotification) bus.SentMessages[1].Message;

            Assert.AreEqual(2, statusUpdate.EndpointMeasurements.Count);
            Assert.AreEqual("TestProbe1", statusUpdate.EndpointMeasurements[0].Name);
            Assert.AreEqual("TestProbe2", statusUpdate.EndpointMeasurements[1].Name);
            Assert.AreEqual("1.15457", statusUpdate.EndpointMeasurements[1].Value);
            Assert.That(statusUpdate.StatusExpirationUtcTime, Is.LessThanOrEqualTo(
                                                                  DateTime.Now.ToUniversalTime().AddMinutes(10).
                                                                      AddMilliseconds(500)));
            Assert.That(statusUpdate.StatusExpirationUtcTime, Is.GreaterThanOrEqualTo(
                                                                  DateTime.Now.ToUniversalTime().AddMinutes(9).
                                                                      AddMilliseconds(500)));
        }
    }
}